#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <setjmp.h>
#include <signal.h>

#define MAX_SIZE 65535

char buf[MAX_SIZE+1];

static sigjmp_buf jmpbuf;
static void alarm_func(){
    siglongjmp(jmpbuf, 1);
}

// s_fd: socket file descriptor
void print_response(int s_fd, char *buf){
    signal(SIGALRM, alarm_func);
    if (sigsetjmp(jmpbuf, 1) != 0){ // 超时
        alarm(0);
        signal(SIGALRM, SIG_IGN);
        return ;
    }
    alarm(1);
    signal(SIGALRM, alarm_func);
    int r_size;
    while (r_size = recv(s_fd, buf, MAX_SIZE, 0)){
        if (r_size == -1){
            perror("recv");
            exit(EXIT_FAILURE);
        }
        buf[r_size] = '\0'; 
        printf("%s", buf);
        alarm(1);
        signal(SIGALRM, alarm_func);
    }
}

void recv_mail()
{
    const char* host_name = "pop.163.com"; // Specify the mail server domain name
    const unsigned short port = 110; // POP3 server port
    const char* user = "user mail_lab_test@163.com\r\n"; // Specify the user
    const char* pass = "pass OEUDQYINOTFJCYGJ\r\n"; // Specify the password
    char dest_ip[16];
    int s_fd; // socket file descriptor
    struct hostent *host;
    struct in_addr **addr_list;
    int i = 0;
    int r_size;

    // Get IP from domain name
    if ((host = gethostbyname(host_name)) == NULL)
    {
        herror("gethostbyname");
        exit(EXIT_FAILURE);
    }

    addr_list = (struct in_addr **) host->h_addr_list;
    while (addr_list[i] != NULL)
        ++i;
    strcpy(dest_ip, inet_ntoa(*addr_list[i-1]));

    // Create a socket,return the file descriptor to s_fd, and establish a TCP connection to the POP3 server
    s_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (s_fd == -1){
        perror("create a socket");
        exit(EXIT_FAILURE);
    }
    // 连接服务器
    struct sockaddr_in sad_in = {
        .sin_port = htons(port),
        .sin_family = AF_INET,
        .sin_addr.s_addr = inet_addr(dest_ip)//addr_list[i-1]->s_addr
    };
    if (connect(s_fd, (struct sockaddr *)&sad_in, sizeof(sad_in)) == -1){
        perror("connect");
        exit(EXIT_FAILURE);
    }

    // Print welcome message
    print_response(s_fd, buf);

    // Send user and password and print server response
    send(s_fd, user, strlen(user), 0);
    print_response(s_fd, buf);
    
    send(s_fd, pass, strlen(pass), 0);
    print_response(s_fd, buf);

    // Send LIST command and print server response
    const char *LIST = "list\r\n";
    send(s_fd, LIST, strlen(LIST), 0);
    print_response(s_fd, buf);

    // Retrieve the first mail and print its content
    const char *RETR = "retr 1\r\n";
    send(s_fd, RETR, strlen(RETR), 0);
    print_response(s_fd, buf);

    // Send QUIT command and print server response
    const char *QUIT = "quit\r\n";
    send(s_fd, QUIT, strlen(QUIT), 0);
    print_response(s_fd, buf);

    close(s_fd);
}

int main(int argc, char* argv[])
{
    recv_mail();
    exit(0);
}
